//---------------------------------------------------------------------------------------
// uart receive module  
//
//---------------------------------------------------------------------------------------

module uart_rx 
(
	clock, reset,
	ce_16, ser_in, 
	rx_data, new_rx_data 
);
//---------------------------------------------------------------------------------------
// modules inputs and outputs 
input 			clock;			// global clock input 
input 			reset;			// global reset input 
input			ce_16;			// baud rate multiplyed by 16 - generated by baud module 
input			ser_in;			// serial data input 
output	[7:0]	rx_data;		// data byte received 
output 			new_rx_data;	// signs that a new byte was received 

// internal wires 
wire ce_1;		// clock enable at bit rate 
wire ce_1_mid;	// clock enable at the middle of each bit - used to sample data 

// internal registers 
reg	[7:0] rx_data;
reg	new_rx_data;
reg [1:0] in_sync;
reg rx_busy; 
reg [3:0]	count16;
reg [3:0]	bit_count;
reg [7:0]	data_buf;
//---------------------------------------------------------------------------------------
// module implementation 
// input async input is sampled twice 
always @ (posedge clock or posedge reset)
begin 
	if (reset) 
		in_sync <= 2'b11;
	else 
		in_sync <= {in_sync[0], ser_in};
end 

// a counter to count 16 pulses of ce_16 to generate the ce_1 and ce_1_mid pulses.
// this counter is used to detect the start bit while the receiver is not receiving and 
// signs the sampling cycle during reception. 
always @ (posedge clock or posedge reset)
begin
	if (reset) 
		count16 <= 4'b0;
	else if (ce_16) 
	begin 
		if (rx_busy | (in_sync[1] == 1'b0))
			count16 <= count16 + 4'b1;
		else 
			count16 <= 4'b0;
	end 
end 

// ce_1 pulse indicating expected end of current bit 
assign ce_1 = (count16 == 4'b1111) & ce_16;
// ce_1_mid pulse indication the sampling clock cycle of the current data bit 
assign ce_1_mid = (count16 == 4'b0111) & ce_16;

// receiving busy flag 
always @ (posedge clock or posedge reset)
begin 
	if (reset)
		rx_busy <= 1'b0;
	else if (~rx_busy & ce_1_mid)
		rx_busy <= 1'b1;
	else if (rx_busy & (bit_count == 4'h8) & ce_1_mid) 
		rx_busy <= 1'b0;
end 

// bit counter 
always @ (posedge clock or posedge reset)
begin 
	if (reset)
		bit_count <= 4'h0;
	else if (~rx_busy) 
		bit_count <= 4'h0;
	else if (rx_busy & ce_1_mid)
		bit_count <= bit_count + 4'h1;
end 

// data buffer shift register 
always @ (posedge clock or posedge reset)
begin 
	if (reset)
		data_buf <= 8'h0;
	else if (rx_busy & ce_1_mid)
		data_buf <= {in_sync[1], data_buf[7:1]};
end 

// data output and flag 
always @ (posedge clock or posedge reset)
begin 
	if (reset) 
	begin 
		rx_data <= 8'h0;
		new_rx_data <= 1'b0;
	end 
	else if (rx_busy & (bit_count == 4'h8) & ce_1)
	begin 
		rx_data <= data_buf;
		new_rx_data <= 1'b1;
	end 
	else 
		new_rx_data <= 1'b0;
end 

endmodule
//---------------------------------------------------------------------------------------
//						Th.. Th.. Th.. Thats all folks !!!
//---------------------------------------------------------------------------------------
